﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caliburn.Core.Metadata;
using XWord.Fundamental.Domain;
using XWord.Fundamental.Domain.Model;
using Microsoft.Practices.ServiceLocation;
using Caliburn.PresentationFramework;
using System.Threading;
using XWord.WPF.ApplicationFramework;
using Caliburn.PresentationFramework.ApplicationModel;
using System.Windows.Media;
using System.Net;
using System.IO;
using System.Xml;
using System.Collections;
using Caliburn.PresentationFramework.Actions;
using System.Collections.ObjectModel;
using Microsoft.Win32;
using XWord.GUI.Presenters.Infrastructure;
using XWord.GUI.Presenters.Fundamental;


namespace XWord.GUI.Presenters
{
    [Singleton(typeof(ShellPresenter))]
    public class ShellPresenter : Presenter
    {
        private IWordModel _wordModel;
        private IAlphabetModel _alphabetModel;
        private IServiceLocator _serviceLocator;
        public ShellPresenter(IServiceLocator entityFactory)
        {
            _serviceLocator = entityFactory;
            _wordModel = _serviceLocator.GetInstance<IWordModel>();
            _alphabetModel = _serviceLocator.GetInstance<IAlphabetModel>();
            AlphabetList = _alphabetModel.GetAlphabetList();
        }

        public IList<Alphabet> AlphabetList { get; set; }

        protected override void OnInitialize()
        {
            AllWordList = _wordModel.LoadWordList().OrderBy(e => e.Name).OrderBy(e => e.IsIgnore).ToObservableCollection();
            //foreach (var item in AllWordList)
            //{
            //    item.UpdateTime = DateTime.Now;
            //    item.CreateTime = DateTime.Now;
            //    _wordModel.SaveWord(item);
            //}
            NotFamilarCount = AllWordList.Count(e => !e.IsIgnore);
            NotEtymaCount = AllWordList.Count(e => string.IsNullOrEmpty(e.Suffix));
            EtymaLibraryPresenter.Initialize();
            CategoryPresenter.Initialize();
            base.OnInitialize();
        }



        public void DisplayNotFamilarWordList()
        {
            WordList = AllWordList.Where(e => !e.IsIgnore).ToObservableCollection();
        }

        public void DisplayNotEtymaWordList()
        {
            WordList = AllWordList.Where(e => string.IsNullOrEmpty(e.Suffix)).ToObservableCollection();
        }

        public void DisplayTodayWordList()
        {
            
            WordList = AllWordList.Where(e => CheckWordUpdateTime(e.UpdateTime)).ToObservableCollection();
        }

        public IList<EtymaLibrary> AllEtymaLibraryList { get; set; }
        public IList<Word> AllWordList { get; set; }

        private IPresenter _categoryPresenter;
        public IPresenter CategoryPresenter
        {
            get { return _categoryPresenter ?? (_categoryPresenter = _serviceLocator.GetInstance<CategoryMasterPresenter>()); }
            set { _categoryPresenter = value; }
        }

        private IEtymaLibraryMasterScreen _etymaLibraryPresenter;
        public IEtymaLibraryMasterScreen EtymaLibraryPresenter
        {
            get { return _etymaLibraryPresenter ?? (_etymaLibraryPresenter = _serviceLocator.GetInstance<EtymaLibraryMasterPresenter>()); }
            set { _etymaLibraryPresenter = value; }
        }

        private IList<Word> _wordList;
        public IList<Word> WordList
        {
            get { return _wordList ?? (_wordList = new List<Word>()); }
            set
            {
                _wordList = value;
                NotifyOfPropertyChange("WordList");
            }
        }

        public void OpenWordSearchDialog()
        {
            var presenter = ServiceLocator.Current.GetInstance<IWordFinderPresenter>();
            WordList = AllWordList;
            presenter.WordItems = WordList;
            ServiceLocator.Current.GetInstance<IWindowManager>()
                .Show(presenter, null, ExecuteShutdownModel);

        }

        public void OpenOptionDialog()
        {
            var presenter = ServiceLocator.Current.GetInstance<OptionManagerPresenter>();

            ServiceLocator.Current.GetInstance<IWindowManager>()
                .Show(presenter, null, ExecuteShutdownModel);
        }

        public void OpenLCArticleDialog()
        {
            var presenter = ServiceLocator.Current.GetInstance<LCArticlePresenter>();

            ServiceLocator.Current.GetInstance<IWindowManager>()
                .Show(presenter, null, ExecuteShutdownModel);
            //presenter.WordItems = this.WordList;
        }

        public void OpenTranslateDialog()
        {
            var presenter = ServiceLocator.Current.GetInstance<TranslatePresenter>();

            ServiceLocator.Current.GetInstance<IWindowManager>()
                .Show(presenter, null, ExecuteShutdownModel);
            //presenter.WordItems = this.WordList;
        }

        

        public void OpenRCArticleDialog()
        {
            var presenter = ServiceLocator.Current.GetInstance<RCArticlePresenter>();

            ServiceLocator.Current.GetInstance<IWindowManager>()
                .Show(presenter, null, ExecuteShutdownModel);
            //presenter.WordItems = this.WordList;
        }

        public void ReadSelectedWord(string name)
        {
            DefaultReadWordEngine.UseDefaultReadWord(name);
        }

        private static IList<EtymaMessage> ParseText(string text)
        {
            var etymas = text.Split(new char[] { ',' });
            IList<EtymaMessage> messageList = new List<EtymaMessage>();
            for (int i = 0; i < etymas.Length; i++)
            {
                var message = new EtymaMessage(etymas[i].Trim());
                if (!string.IsNullOrEmpty(message.Name))
                {
                    messageList.Add(message);
                }
            }
            return messageList;
        }

        public void SearchEtyma(string text)
        {
            if (string.IsNullOrEmpty(text))
                return;

            if (SearchMode > 0)
            {
                SearchWord(SearchText);
            }
            else
            {
                EtymaLibraryPresenter.EtymaLibraryList = EtymaLibraryPresenter.AllEtymaLibraryList.
                    Where(e =>EtymaUtil.ParseText(e.Name).Any(m => m.Name.StartsWith(SearchText))).Take(20).ToObservableCollection();
            }
        }

        public void SearchEtymaWord(string EtymaorWord)
        {
            if (string.IsNullOrEmpty(EtymaorWord)) return;
            IList<EtymaMessage> messageList = ParseText(EtymaorWord);
            if (messageList.Any(e => e.EtymaType == EtymaType.Etymon))
            {
                WordList = AllWordList.Where(e => messageList.Any(msg => e.Name.Contains(msg.Name))).ToList();
            }
            else
            {
                WordList = AllWordList.Where(e => messageList.Any
                    (msg => (e.Name.StartsWith(msg.Name) && msg.EtymaType == EtymaType.PreFix)
                    || (e.Name.EndsWith(msg.Name) && msg.EtymaType == EtymaType.Suffix)))
                    .ToList();
            }
        }

        private bool CheckWordLength(string word, string searchName)
        {
            int count = 0;
            var countStr = searchName.Split(new char[] { ':' });
            if (countStr.Length > 1 && !string.IsNullOrEmpty(countStr[1]))
                count = int.Parse(countStr[1]);
            if (count > 0)
                return word.Length == count;
            return true;
        }

        private bool SearchFilerWord(string word, string searchName)
        {
            if (searchName.Contains(":"))
            {
                searchName = searchName.Substring(0, searchName.IndexOf(":"));
            }
            var length = searchName.Length;
            var array=searchName.Split(new char[]{'*'});

            if (array.Length == 1)
                return word.StartsWith(searchName);
            if (array.Length == 2)
            {
                if (string.IsNullOrEmpty(array[0]))
                    return word.EndsWith(array[1]);
                else
                    return word.StartsWith(array[0]) && word.EndsWith(array[1]);
            }

            if (array.Length >= 3)
            {
                var list = new List<bool>();
                for (int i = 0; i < (array.Length - 2); i++)
                {
                    list.Add(word.Substring(searchName.IndexOf("*")).Contains(array[i + 1]));
                }
                return ChcekStartEnd(word, array[0], true) && !list.Contains(false) && ChcekStartEnd(word, array[array.Length - 1], false);
            }
            //a*ion,*ion
            return true;
        }

        private bool ChcekStartEnd(string word, string searchName, bool IsStart)
        {
            if (string.IsNullOrEmpty(searchName)) return true;
            if (IsStart)
                return word.StartsWith(searchName);
            else
                return word.EndsWith(searchName);
        }

        private void SearchWord(string Name)
        {
            Name = Name.ToLower().Trim();
            WordList = AllWordList.Where(e =>CheckWordLength(e.Name.ToLower(), Name.ToLower()) && SearchFilerWord(e.Name.ToLower(), Name.ToLower())).ToObservableCollection();
        }

        public void SearchWordEtyma()
        {
            if (string.IsNullOrEmpty(SearchText)) return;
            EtymaLibraryPresenter.EtymaLibraryList = EtymaLibraryPresenter.AllEtymaLibraryList.
                    Where(e => ParseText(e.Name).Any(m =>
                       (SearchText.Contains(m.Name))
                        )).ToObservableCollection();
        }

        public void SaveWord(Word word)
        {
            _wordModel.SaveWord(word);
            NotEtymaCount = AllWordList.Count(e => string.IsNullOrEmpty(e.Suffix));
        }

        public void AddWord()
        {
            WordImport import = new WordImport();
            import.ImportWord(SearchText,
                (Word word) => { return !AllWordList.Any(ee => ee.Name.Trim() == word.Name); },
                ((Word word) =>
                {
                    word.CreateTime = DateTime.Now;
                    
                    _wordModel.SaveWord(word);
                    AllWordList.Add(word);
                    SearchWord(SearchText);
                }));
        }

        public void MarkIsIgnore(Word word)
        {
            word.IsIgnore = !word.IsIgnore;
            _wordModel.SaveWord(word);
            NotFamilarCount = AllWordList.Count(e => !e.IsIgnore);
            NotEtymaCount = AllWordList.Count(e => string.IsNullOrEmpty(e.Suffix));
        }

        private int _notFamilarCount;
        public int NotFamilarCount
        {
            get { return _notFamilarCount; }
            set
            {
                _notFamilarCount = value;
                NotifyOfPropertyChange("NotFamilarCount");
            }
        }

        private int _notEtymaCount;
        public int NotEtymaCount
        {
            get { return _notEtymaCount; }
            set
            {
                _notEtymaCount = value;
                NotifyOfPropertyChange("NotEtymaCount");
            }
        }

        public Word SelectedWord { get; set; }

        public void CopyWordToSearch()
        {
            SearchText = SelectedWord.Name;
        }

        public void DeleteWord()
        {
            _wordModel.DeleteWord(SelectedWord);
            AllWordList.Remove(SelectedWord);
        }

        [AsyncAction]
        public void ImportWordList()
        {
            WordImport import = new WordImport();
            import.Excute(
                (Word word) => { return !AllWordList.Any(ee => ee.Name.Trim() == word.Name); },
                ((Word word) =>{
                    _wordModel.SaveWord(word);
                    AllWordList.Add(word);
                }));
        }

        public void ExportTodayWordList()
        {
            var list = AllWordList.Where(e => CheckWordUpdateTime(e.UpdateTime)).ToList();
            Newtonsoft.Json.JsonSerializer js = new Newtonsoft.Json.JsonSerializer();
            var a = new StringWriter();
            js.Serialize(a, list);
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.DefaultExt = "txt";
            dialog.AddExtension = true;
            var result = dialog.ShowDialog();
            if (result.Value)
            {
                using (StreamWriter sw = File.CreateText(dialog.FileName))
                {
                    sw.WriteLine(a.ToString());
                }
            }
            a.Close();
        }

        public void ExportSelectedWordList(IList list)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.DefaultExt = "txt";
            dialog.AddExtension = true;
            var result = dialog.ShowDialog();
            if (result.Value)
            {
                using (StreamWriter sw = File.CreateText(dialog.FileName))
                {
                    foreach (Word item in list)
                    {
                        sw.WriteLine(string.Format("{0} {1}",item.Name,item.Suffix));
                    }
                }
            }
            
        }

        public void ImportTodayWordList()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            var result = dialog.ShowDialog();
            if (result.Value)
            {

                using (TextReader streamReader =
                   new StreamReader(dialog.FileName, Encoding.UTF8))
                {
                    Newtonsoft.Json.JsonSerializer js = new Newtonsoft.Json.JsonSerializer();
                    var list= js.Deserialize(new StringReader(streamReader.ReadToEnd()), typeof(IList)) as IList;
                    foreach (Newtonsoft.Json.Linq.JObject item in list)
                    {
                        var jvalue = item["Name"] as Newtonsoft.Json.Linq.JValue;
                       
                        var word=AllWordList.Where(e => e.Name == jvalue.Value.ToString());
                        if (word.Count() > 0)
                        {
                            var currentWord = word.First();
                            currentWord.Suffix = (item["Suffix"] as Newtonsoft.Json.Linq.JValue).Value.ToString();
                            currentWord.IsIgnore = true;
                            _wordModel.SaveWord(currentWord);
                        }
                        else
                        {
                            WordImport import = new WordImport();
                            import.ImportWord(jvalue.Value.ToString(),
                                (Word word1) => { return !AllWordList.Any(ee => ee.Name.Trim() == word1.Name); },
                                ((Word word1) =>
                                {
                                    word1.CreateTime = DateTime.Now;
                                    _wordModel.SaveWord(word1);
                                    AllWordList.Add(word1);
                                    //SearchWord(SearchText);
                                }));
                        }
                    }
                }
            }
        }

        private bool CheckWordUpdateTime(DateTime? time)
        {
            if (!time.HasValue) return false;
            var value=time.Value;
            var now=DateTime.Now;
            return value.Year == now.Year && value.Month == now.Month && value.Day == now.Day;
        }

        public void SearchWordByCategory(Category category)
        {
            // SearchFactory.CreateSearchObject<CategorySearch>(category).BeginQuery(WordList);
        }

        public void SearchWordByAlphabet(Alphabet entity)
        {
            if (entity == null) return;
            SearchText = entity.Name;
            // WordList = AllWordList.Where(e => e.Name.ToLower().StartsWith(text.ToLower())).ToList();
        }

        public void SaveAlphabet(object entity)
        {
            if (entity == null) return;
            _alphabetModel.SaveAlphabet(entity as Alphabet);
        }

        private string _searchText;
        public string SearchText
        {
            get { return _searchText; }
            set
            {
                _searchText = value;
                NotifyOfPropertyChange("SearchText");
            }
        }

        private int _searchMode;
        public int SearchMode
        {
            get { return XWordAppConfig.Current.SearchTarget; }
            set
            {
                XWordAppConfig.Current.SearchTarget = value;
                NotifyOfPropertyChange("SearchMode");
            }
        }


    }
}
